package com.spring.common.redis;

import com.spring.common.redis.config.JedisClusterFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;

/**
 * jedis管理类
 *
 * @author anpushang
 */
public class JedisManager extends JedisClusterFactory {


	private static final Log logger = LogFactory.getLog(JedisManager.class);

	/**
	 * 设置字符串
	 * @param key
	 * @param str
	 * @param seconds
	 * @return
	 */
	public static String setString(String key, String str, int seconds) {
		if ((key == null) || (str == null))
			return null;
		String ret = null;
		try {
			if (seconds <= 0)
				// 永久保存
				ret = jedisCluster.set(encode(key), str);
			else
				// 设置有效期
				ret = jedisCluster.setex(encode(key), seconds, str);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("key:" + key + "redis存储出错.");
		}
		return ret;
	}

	/**
	 * 更新过期时间
	 *
	 * @param key
	 * @param seconds
	 */
	public static void setEx(String key, int seconds) {
		if (StringUtils.isNotBlank(key)) {
			try {
				if (jedisCluster.exists(key)) {
					jedisCluster.expire(key, seconds);
				}
			} catch (Exception e) {
				logger.error("key:" + seconds + "更新过期时间出错.");
			}
		}
	}


	/**
	 * 判断是否存在改key
	 *
	 * @param key
	 * @return
	 */
	public static boolean exists(String key) {
		boolean exists = false;
		if (!"".equals(key)) {
			try {
				return jedisCluster.exists(key);
			} catch (Exception e) {
				logger.error("key:" + key + "查询.");
			}
		}
		return exists;
	}

	/***
	 * 根据key值获取redis存储内容
	 *
	 * @param key
	 * @return
	 */
	public static String getString(String key) {
		String ret = null;
		try {
			ret = jedisCluster.get(encode(key));
		} catch (Exception e) {
			logger.error("key:" + key + "未能取到redis的值.");
		}
		return ret;
	}


	/***
	 * redis存储类型为列表，相当于list
	 * 如果 key 不存在，一个空列表会被创建并执行 LPUSH 操作。
	 *
	 * @param key
	 * @return
	 */
	public static Long lPush(final String key, String... value) {
		Long ret = null;
		try {
			ret = jedisCluster.lpush(encode(key), value);
		} catch (Exception e) {
			logger.error("key:" + key + "未能 lpush值..");
		}
		return ret;
	}

	/****
	 * 获取redis列表的值
	 * @param key redis key
	 * @param start 开始角标
	 * @param end 结束角标
	 * @return
	 */
	public static List<String> lrange(final String key, final long start, final long end){
		List<String> resultList = null;
		try{
			jedisCluster.lrange(key,start,end);
		}catch (Exception e){
			logger.error("key:" + key + "未能取到redis的值.");
		}
		return resultList;
	}

	/****
	 * 存储 redis list数据，当 key 不存在时， LPUSHX 命令什么也不做
	 * @param key
	 * @param string
	 * @return
	 */
	public static Long lpushx(final String key, final String... string){
		Long ret = null;
		try {
			ret = jedisCluster.lpush(encode(key), string);
		} catch (Exception e) {
			logger.error("key:" + key + "未能 lpush值..");
		}
		return ret;
	}
	/***
	 * 根据key值移除redis列表中的头元素，也就是list(0)的元素，
	 *
	 * @param key
	 * @return
	 */
	public static String lPop(String key) {
		String ret = null;
		try {
			ret = jedisCluster.lpop(encode(key));
		} catch (Exception e) {
			logger.error("key:" + key + "未能移除redis的值.");
		}
		return ret;
	}

	/****
	 * 根据参数 count 的值，移除列表中与参数 value 相等的元素
	 * count > 0 : 从表头开始向表尾搜索，移除与 value 相等的元素，数量为 count 。
	   count < 0 : 从表尾开始向表头搜索，移除与 value 相等的元素，数量为 count 的绝对值。
	   count = 0 : 移除表中所有与 value 相等的值
	 * @param key
	 * @param count
	 * @param value
	 * @return
	 */
	public static Long lrem(final String key, final long count, final String value){
		Long result = null;
		try{
			jedisCluster.lrem(key,count,value);
		}catch (Exception e){
			logger.error("key:" + key + "未能移除redis的值.");
		}
		return result;
	}

	/***
	 * 获取reids列表中的某个角标的数据
	 * @param key
	 * @param index
	 * @return
	 */
	public static String lindex(final String key, final long index){
		String result = null;
		try {
			result = jedisCluster.lindex(key,index);
		}catch (Exception e){
			logger.error("key:" + key + "未能 lindex值..");
		}
		return result;
	}



	/***
	 *
	 * @param key
	 * @return
	 */
	public static long del(byte[] key) {
		if (key == null) {
			return 0L;
		}
		long ret = 0L;
		try {
			ret = jedisCluster.del(key).longValue();
		} catch (Exception e) {
			logger.error(e);
			ret = -1L;
		}
		return ret;
	}

	/**
	 * 根据redis key for delete
	 *
	 * @param key
	 * @return
	 */
	public static long del(String key) {
		if (key == null) {
			return 0L;
		}
		long ret = 0L;
		try {
			ret = jedisCluster.del(key).longValue();
		} catch (Exception e) {
			logger.error(e);
			ret = -1L;
		}
		return ret;
	}

	/**
	 * 根据redis key for delete
	 *
	 * @param key
	 * @return
	 */
	public static long del(String... key) {
		if (key == null) {
			return 0L;
		}
		long ret = 0L;
		try {
			ret = jedisCluster.del(key).longValue();
		} catch (Exception e) {
			logger.error(e);
			ret = -1L;
		}
		return ret;
	}



	/**
	 * 分布式锁
	 *
	 * @param key
	 * @param seconds(加锁时长)
	 * @return
	 */
	public static boolean lock(String key, int seconds) {
		if (seconds <= 0) {
			seconds = 21600;
		}
		boolean result = false;
		if (key == null)
			return result;
		long currentTime = System.currentTimeMillis();
		long expireTime = currentTime + seconds * 1000;
		try {
			if (jedisCluster.setnx(encode(key), String.valueOf(expireTime)).longValue() == 1L) {
				result = true;
				jedisCluster.expire(encode(key), seconds);
			} else {
				//防止死锁
				Long oldExpireTime = Long.valueOf(getString(encode(key)));
				if ((oldExpireTime != null) && (currentTime > oldExpireTime.longValue())) {
					del(encode(key));
					if (jedisCluster.setnx(encode(key), String.valueOf(expireTime)).longValue() == 1L) {
						result = true;
						jedisCluster.expire(encode(key), seconds);
					}
				}
			}
		} catch (Exception e) {
			logger.error(e);
		}
		return result;
	}


	public static boolean setnx(String key,String value){
		try {
			Long setnx = jedisCluster.setnx(key, value);
			if(setnx== 1L){
				return true;
			}
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("key:" + key + "redis存储出错.");
		}
		return false;
	}



	public static Object getObject(String key) {
		if (key == null)
			return null;
		byte[] ret = getBytes(key.getBytes());
		if (ret == null)
			return null;
		return ObjectBytesExchange.toObject(ret);
	}


	public static String setObject(String key, int seconds, Object obj) {
		String returnStr = null;
		try {
			if ((key == null) || (obj == null))
				return null;
			byte[] byteObj = ObjectBytesExchange.toByteArray(obj);
			if (null == byteObj)
				return null;
			returnStr = setBytes(key.getBytes(), seconds, byteObj);
			logger.debug(key + "  Redis存储结果：" + returnStr);
		}catch (Exception e){
			logger.error(e);
		}
		return returnStr;
	}

	public static byte[] getBytes(byte[] key) {
		if (key == null)
			return null;
		byte[] ret = null;
		try {
			ret = jedisCluster.get(key);
		} catch (Exception e) {
			logger.error(e);
		}
		return ret;
	}

	public static String setBytes(byte[] key, int seconds, byte[] bytes) {
		if ((key == null) || (bytes == null))
			return null;
		String ret = null;
		try {
			if (seconds <= 0)
				ret = jedisCluster.set(key, bytes);
			else
				ret = jedisCluster.setex(key, seconds, bytes);
		} catch (Exception e) {
			logger.error(e);
		}
		return ret;
	}

	public static String encode(String str) {
		String ret = null;
		if (str != null) {
			try {
				ret = URLEncoder.encode(str,"UTF-8");
			} catch (UnsupportedEncodingException e) {
				logger.error(e);
			}
		}
		return ret;
	}


}
